package com.reactim.message.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validator;
import java.util.Set;

/**
 * 配置验证器
 * 在应用启动时验证所有配置的有效性
 * 提供友好的错误信息和修复建议
 */
@Component
@Slf4j
public class ConfigurationValidator {
    
    @Autowired
    private ReactimConfig reactimConfig;
    
    @Autowired
    private PerformanceTestConfig performanceTestConfig;
    
    @Autowired
    private Validator validator;
    
    /**
     * 应用启动完成后验证配置
     */
    @EventListener
    public void validateConfiguration(ApplicationReadyEvent event) {
        log.info("开始验证ReactIM配置...");
        
        try {
            validateReactimConfig();
            validatePerformanceTestConfig();
            validateConfigurationConsistency();
            
            log.info("ReactIM配置验证完成，所有配置项均有效");
        } catch (ConfigurationException e) {
            log.error("配置验证失败: {}", e.getMessage());
            // 暂时不抛出异常，允许服务启动
            log.warn("配置验证失败，但允许服务继续启动。请检查配置后重启服务。");
        } catch (Exception e) {
            log.error("配置验证过程中发生未知错误", e);
            // 暂时不抛出异常，允许服务启动
            log.warn("配置验证过程中发生错误，但允许服务继续启动。请检查配置后重启服务。");
        }
    }
    
    /**
     * 验证ReactIM主配置
     */
    private void validateReactimConfig() {
        Set<ConstraintViolation<ReactimConfig>> violations = validator.validate(reactimConfig);
        if (!violations.isEmpty()) {
            StringBuilder sb = new StringBuilder("ReactIM配置验证失败:\n");
            for (ConstraintViolation<ReactimConfig> violation : violations) {
                sb.append("- ").append(violation.getPropertyPath()).append(": ").append(violation.getMessage()).append("\n");
            }
            throw new ConfigurationException("reactim", sb.toString(), "请检查application.yml中的reactim配置项");
        }
        
        // 验证连接配置
        validateConnectionConfig();
        
        // 验证消息配置
        validateMessageConfig();
        
        // 验证性能配置
        validatePerformanceConfig();
    }
    
    /**
     * 验证连接配置
     */
    private void validateConnectionConfig() {
        ReactimConfig.ConnectionProperties connection = reactimConfig.getConnection();
        
        // 验证过期时间
        if (connection.getExpirationTime() <= 0) {
            throw new ConfigurationException("reactim.connection.expiration-time", 
                "连接过期时间必须大于0", "建议设置为30分钟以上",
                "reactim:\n  connection:\n    expiration-time: 30  # 30分钟");
        }
        
        // 验证清理间隔
        if (connection.getCleanupInterval() <= 0) {
            throw new ConfigurationException("reactim.connection.cleanup-interval", 
                "清理任务执行间隔必须大于0", "建议设置为5分钟以上",
                "reactim:\n  connection:\n    cleanup-interval: 5  # 5分钟");
        }
        
        // 验证Redis配置
        ReactimConfig.ConnectionProperties.RedisProperties redis = connection.getRedis();
        if (!StringUtils.hasText(redis.getKeyPrefix())) {
            throw new ConfigurationException("reactim.connection.redis.key-prefix", 
                "Redis键前缀不能为空", "建议设置为'reactim:connection:'",
                "reactim:\n  connection:\n    redis:\n      key-prefix: 'reactim:connection:'");
        }
        
        // 验证安全配置
        ReactimConfig.ConnectionProperties.SecurityProperties security = connection.getSecurity();
        if (security.isEnableEncryption() && !StringUtils.hasText(security.getEncryptionKey())) {
            log.warn("启用了数据加密但未设置加密密钥，将使用默认密钥（不推荐用于生产环境）");
        }
        
        if (security.getMaxConnectionsPerUser() <= 0) {
            throw new ConfigurationException("reactim.connection.security.max-connections-per-user", 
                "每个用户最大连接数必须大于0", "建议设置为5-20之间",
                "reactim:\n  connection:\n    security:\n      max-connections-per-user: 5  # 每个用户最多5个连接");
        }
        
        // 验证监控配置
        ReactimConfig.ConnectionProperties.MonitoringProperties monitoring = connection.getMonitoring();
        if (monitoring.getHeartbeatIntervalMs() <= 0) {
            throw new ConfigurationException("reactim.connection.monitoring.heartbeat-interval-ms", 
                "心跳检测间隔必须大于0", "建议设置为30000毫秒（30秒）",
                "reactim:\n  connection:\n    monitoring:\n      heartbeat-interval-ms: 30000  # 30秒");
        }
        
        // 验证缓存配置
        ReactimConfig.ConnectionProperties.CacheProperties cache = connection.getCache();
        if (cache.getConnectionCacheMaxSize() <= 0) {
            throw new ConfigurationException("reactim.connection.cache.connection-cache-max-size", 
                "连接缓存最大容量必须大于0", "建议设置为10000以上",
                "reactim:\n  connection:\n    cache:\n      connection-cache-max-size: 10000  # 缓存10000个连接");
        }
    }
    
    /**
     * 验证消息配置
     */
    private void validateMessageConfig() {
        ReactimConfig.MessageProperties message = reactimConfig.getMessage();
        
        if (message.getRecallTimeLimit() <= 0) {
            throw new ConfigurationException("reactim.message.recall-time-limit", 
                "消息撤回时间限制必须大于0", "建议设置为2分钟以上",
                "reactim:\n  message:\n    recall-time-limit: 2  # 2分钟");
        }
        
        if (message.getMaxContentLength() <= 0) {
            throw new ConfigurationException("reactim.message.max-content-length", 
                "消息最大长度必须大于0", "建议设置为10000字符以上",
                "reactim:\n  message:\n    max-content-length: 10000  # 10000字符");
        }
        
        if (message.getMaxFileSize() <= 0) {
            throw new ConfigurationException("reactim.message.max-file-size", 
                "文件消息最大大小必须大于0", "建议设置为100MB以下",
                "reactim:\n  message:\n    max-file-size: 100  # 100MB");
        }
        
        // 验证路由配置
        ReactimConfig.MessageProperties.RoutingProperties routing = message.getRouting();
        if (!StringUtils.hasText(routing.getKafka().getTopic())) {
            throw new ConfigurationException("reactim.message.routing.kafka.topic", 
                "Kafka主题不能为空", "建议设置为'cross-instance-messages'",
                "reactim:\n  message:\n    routing:\n      kafka:\n        topic: 'cross-instance-messages'");
        }
        
        if (routing.getRetry().getMaxAttempts() <= 0) {
            throw new ConfigurationException("reactim.message.routing.retry.max-attempts", 
                "最大重试次数必须大于0", "建议设置为3次",
                "reactim:\n  message:\n    routing:\n      retry:\n        max-attempts: 3  # 最多重试3次");
        }
    }
    
    /**
     * 验证性能配置
     */
    private void validatePerformanceConfig() {
        ReactimConfig.PerformanceProperties performance = reactimConfig.getPerformance();
        
        if (performance.getReport().getInterval() <= 0) {
            throw new ConfigurationException("reactim.performance.report.interval", 
                "性能报告生成间隔必须大于0", "建议设置为300000毫秒（5分钟）",
                "reactim:\n  performance:\n    report:\n      interval: 300000  # 5分钟");
        }
    }
    
    /**
     * 验证性能测试配置
     */
    private void validatePerformanceTestConfig() {
        Set<ConstraintViolation<PerformanceTestConfig>> violations = validator.validate(performanceTestConfig);
        if (!violations.isEmpty()) {
            StringBuilder sb = new StringBuilder("性能测试配置验证失败:\n");
            for (ConstraintViolation<PerformanceTestConfig> violation : violations) {
                sb.append("- ").append(violation.getPropertyPath()).append(": ").append(violation.getMessage()).append("\n");
            }
            throw new ConfigurationException("performance.test", sb.toString(), "请检查application.yml中的performance.test配置项");
        }
        
        if (!performanceTestConfig.isValid()) {
            throw new ConfigurationException("performance.test", 
                "性能测试配置无效", "请检查所有必需的配置项是否正确设置");
        }
    }
    
    /**
     * 验证配置一致性
     */
    private void validateConfigurationConsistency() {
        // 验证连接过期时间和清理间隔的一致性
        ReactimConfig.ConnectionProperties connection = reactimConfig.getConnection();
        if (connection.getCleanupInterval() >= connection.getExpirationTime()) {
            log.warn("清理任务执行间隔({})大于等于连接过期时间({})，可能导致连接无法及时清理", 
                connection.getCleanupInterval(), connection.getExpirationTime());
        }
        
        // 验证心跳间隔和不活跃阈值的一致性
        ReactimConfig.ConnectionProperties.MonitoringProperties monitoring = connection.getMonitoring();
        if (monitoring.getHeartbeatIntervalMs() * 3 > monitoring.getInactivityThresholdMs()) {
            log.warn("心跳检测间隔过长，可能导致不活跃连接检测不及时");
        }
        
        // 验证缓存配置的一致性
        ReactimConfig.ConnectionProperties.CacheProperties cache = connection.getCache();
        if (cache.isEnabled() && cache.getConnectionCacheMaxSize() < 1000) {
            log.warn("连接缓存容量较小({}), 在高并发场景下可能影响性能", cache.getConnectionCacheMaxSize());
        }
    }
    
    /**
     * 配置异常类
     */
    public static class ConfigurationException extends RuntimeException {
        private final String configPath;
        private final String suggestion;
        private final String fixExample;
        
        public ConfigurationException(String configPath, String message, String suggestion) {
            this(configPath, message, suggestion, null);
        }
        
        public ConfigurationException(String configPath, String message, String suggestion, String fixExample) {
            super(buildErrorMessage(configPath, message, suggestion, fixExample));
            this.configPath = configPath;
            this.suggestion = suggestion;
            this.fixExample = fixExample;
        }
        
        private static String buildErrorMessage(String configPath, String message, String suggestion, String fixExample) {
            StringBuilder sb = new StringBuilder();
            sb.append("\n").append("=".repeat(80)).append("\n");
            sb.append("❌ ReactIM 配置错误\n");
            sb.append("=".repeat(80)).append("\n");
            sb.append("配置路径: ").append(configPath).append("\n");
            sb.append("错误描述: ").append(message).append("\n");
            sb.append("修复建议: ").append(suggestion).append("\n");
            
            if (fixExample != null) {
                sb.append("配置示例:\n").append(fixExample).append("\n");
            }
            
            sb.append("=".repeat(80));
            return sb.toString();
        }
        
        public String getConfigPath() {
            return configPath;
        }
        
        public String getSuggestion() {
            return suggestion;
        }
        
        public String getFixExample() {
            return fixExample;
        }
    }
}